﻿

#include <stdio.h>
#include "unitycpp/unitycpp_low.h"
#include <exception>
#include <memory>

#include <string>
#include <unordered_map>
#include <codecvt>
#include <locale>
void* sharedbox;

  

struct Sdata
{
public:
	float a1;
	int v2;
	double v3;
};

void _userhandler_OnInit()

{

}
Il2CppObject* testFunc(void* pthis, void* p, MethodInfo* method)
{
	//因为mono内部是u16string，使用u16string操作最快，当然为了内存，可以用ansi，但是需要转换
	std::u16string ustr = std::u16string(u"这玩意儿被CPP劫持了");
	return (Il2CppObject*)ILBridge::il2cpp_string_new_utf16((const Il2CppChar*)ustr.c_str(), ustr.length());
}


size_t stringindex = 0;
struct stringHandle
{
public:
	std::u16string string;
};

std::unordered_map<size_t, stringHandle*> stringhandle;
thread_local Il2CppString* unsafestr = NULL;
thread_local size_t unsafestrpin = 0;

size_t string_new_i()
{
	ILBridge::Test_Log("string_new_i", ILBridge::EnumLogLevel::ERR);

	auto handle = new stringHandle();
	handle->string = std::u16string(u"");
	stringindex++;
	stringhandle[stringindex] = handle;
	return stringindex;

}
size_t string_new_bystring_i(Il2CppString* src)
{
	ILBridge::Test_Log("string_new_bystring_i", ILBridge::EnumLogLevel::ERR);

	auto srcptr = (const char16_t*)ILBridge::il2cpp_string_chars(src);
	ILBridge::Test_Log("string_new_bystring_i 02", ILBridge::EnumLogLevel::ERR);

	auto handle = new stringHandle();
	handle->string = std::u16string(srcptr);
	stringindex++;
	stringhandle[stringindex] = handle;
	ILBridge::Test_Log("string_new_bystring_i 03", ILBridge::EnumLogLevel::ERR);

	return stringindex;
}



size_t string_clone_i(size_t pthis)
{
	ILBridge::Test_Log("string_clone_i", ILBridge::EnumLogLevel::ERR);

	stringHandle* srcHandle = stringhandle[pthis];

	auto handle = new stringHandle();
	handle->string = std::u16string(srcHandle->string);
	stringindex++;
	stringhandle[stringindex] = handle;
	return stringindex;
}
void string_free_i(size_t pthis)
{
	ILBridge::Test_Log("string_free_i", ILBridge::EnumLogLevel::ERR);

	stringHandle* srcHandle = stringhandle[pthis];
	delete srcHandle;
	auto count = stringhandle.erase(pthis);
	if (count == 0)
	{
		stringhandle[pthis] = NULL;
	}
}
Il2CppString* string_getstring_unsafe_i(size_t srcHandleKey)
{
	ILBridge::Test_Log("string_getstring_unsafe_i", ILBridge::EnumLogLevel::ERR);

	if (unsafestr == NULL)
	{
		char16_t buf[2048];
		memset(buf, 0, 2048);
		unsafestr = ILBridge::il2cpp_string_new_utf16((Il2CppChar*)buf, 2048);
		//pin住这个string 不释放，因为我们要拿他做Buf
		unsafestrpin = ILBridge::il2cpp_gchandle_new((Il2CppObject*)unsafestr, true);
	}
	int32_t* plen = (int32_t*)((size_t)unsafestr + sizeof(void*) * 2);
	char16_t* pchar = (char16_t*)((size_t)unsafestr + sizeof(void*) * 2 + 4);

	stringHandle* srcHandle = stringhandle[srcHandleKey];
	int len = (int32_t)srcHandle->string.length();
	if (len > 2048)
		len = 2048;
	*plen = len;

	memcpy(pchar, srcHandle->string.c_str(), len * 2);
	//*pchar = (char16_t*)srcHandle->string.c_str();
	return unsafestr;
}
Il2CppString* string_getstring_safe_i(size_t srcHandleKey)
{
	ILBridge::Test_Log("string_getstring_safe_i", ILBridge::EnumLogLevel::ERR);

	stringHandle* srcHandle = stringhandle[srcHandleKey];
	auto safestr = ILBridge::il2cpp_string_new_utf16((Il2CppChar*)srcHandle->string.c_str(), srcHandle->string.length());
	int32_t* plen = (int32_t*)((size_t)safestr + sizeof(void*) * 2);
	char16_t** pchar = (char16_t**)((size_t)safestr + sizeof(void*) * 2 + 4);

	return safestr;
}
void string_append_i(size_t pthis, size_t  srcHandleKey)
{
	ILBridge::Test_Log("string_append_i", ILBridge::EnumLogLevel::ERR);

	stringHandle* srcHandle = stringhandle[srcHandleKey];

	stringHandle* srcstr = stringhandle[pthis];
	srcstr->string = srcstr->string.append(srcHandle->string);
}

void string_append_string_i(size_t pthis, Il2CppString* src)
{
	ILBridge::Test_Log("string_append_string_i", ILBridge::EnumLogLevel::ERR);

	auto srcptr = (const char16_t*)ILBridge::il2cpp_string_chars(src);

	stringHandle* srcstr = stringhandle[pthis];
	srcstr->string = srcstr->string.append(srcptr);
}
std::wstring_convert<std::codecvt_utf8_utf16<char16_t, 0x10ffff, std::little_endian>, char16_t> strconv;

void string_append_int32_i(size_t pthis, int32_t value)
{
	ILBridge::Test_Log("string_append_int32_i", ILBridge::EnumLogLevel::ERR);

	auto strv = std::to_string(value);
	stringHandle* srcstr = stringhandle[pthis];
	srcstr->string = srcstr->string.append(strconv.from_bytes(strv));
}
void string_append_int32_withcstyleformat_i(size_t pthis, int32_t value, const char* format)
{
	ILBridge::Test_Log("string_append_int32_withcstyleformat_i", ILBridge::EnumLogLevel::ERR);

	char buf[256];
	sprintf(buf, format, value);
	auto strv = std::to_string(value);
	stringHandle* srcstr = stringhandle[pthis];
	srcstr->string = srcstr->string.append(strconv.from_bytes(strv));
}

//传递一个事件，用来处理
void _userhandler_OnEvent(int64_t cmdid, int64_t p1, void* p2)
{
	if (cmdid == 0)
	{ //test method
		if ((int64_t)p1 == 0)
		{
			ILBridge::Test_Call();
		}
		else if ((int64_t)p1 == 1)
		{

			auto type = ILBridge::il2cppex_getclass("UnityEngine", "GameObject");
			void* it = NULL;
			do
			{
				auto ms = ILBridge::il2cpp_class_get_methods(type, &it);
				if (ms != NULL)
				{
					const char* names = ILBridge::il2cpp_method_get_name(ms);

					int ip = 0;
					ip++;
				}
				else
				{
					break;
				}
			} while (it != NULL);

			typedef void* (*icall)(void* pthis, int tag);
			typedef void* (*icallt)(void* pthis);

			if (ILBridge::GetBridgeType() == ILBridge::BridgeType::MONO)
			{
				auto funcc = ILBridge::il2cpp_class_get_method_from_name(type, "CreatePrimitive", -1);
				auto funcc2 = ILBridge::il2cpp_class_get_method_from_name(type, "Internal_CreatePrimitive", -1);
				auto func_getTransform = ILBridge::il2cpp_class_get_method_from_name(type, "get_transfrom", -1);

			}
			else
			{
				//UnityEngine的許多代碼被變爲内部方法了，需要查詢

				//獲取Unity内部方法
				auto func = (icall)ILBridge::il2cpp_resolve_icall
				(
					"UnityEngine.GameObject::CreatePrimitive(UnityEngine.PrimitiveType)"
				);
				//這個可以獲取到，有一些方法，IL2CPP過程中改變過他們,内部方法
				auto funct = (icallt)ILBridge::il2cpp_resolve_icall("UnityEngine.GameObject::get_transform()");

			}
			//枚举，没了，自己当int处理



			int size = ILBridge::il2cpp_class_instance_size(type);
			//這是獲取不到的

			//自動輔助構造函數
			auto obj = ILBridge::ilcppex_object_new(type);

			auto obj2 = ILBridge::ilcppex_object_new<Il2CppString*>(type, ILBridge::il2cpp_string_new("hello"));

		}
		else if ((int64_t)p1 == 2)
		{
			{//创建物体

				auto type = ILBridge::il2cppex_getclass("UnityEngine", "GameObject");
				typedef void* (*icall)(int p);
				typedef void* (*icall2)(int p);

				typedef void* (*tticall2)(void* a, void* p);

				auto tt_functt = ILBridge::il2cpp_resolve_icall(".TestClass.UseS");
				auto tt_type = ILBridge::il2cppex_getclass("", "TestClass");
				auto tt_method = ILBridge::il2cpp_class_get_method_from_name(tt_type, "UseS", -1);
				auto tt_obj = ILBridge::il2cpp_object_new(tt_type);
				ILBridge::il2cpp_runtime_object_init(tt_obj);

				ILBridge::il2cppex_method_Invoke<void>(tt_method, NULL, 0, NULL);
				auto func = (icall)ILBridge::il2cpp_resolve_icall
				(
					"UnityEngine.GameObject::CreatePrimitive(UnityEngine.PrimitiveType)"
				);
				//auto func = (icall)ILBridge::Mono_GetFunc("UnityEngine.GameObject::CreatePrimitive(UnityEngine.PrimitiveType)");
				if (func != nullptr)
				{
					sharedbox = func(3);
				}
			}
			return;
			void* transform = 0;
			void* v3;

			auto str = ILBridge::il2cpp_string_new("__cpp_createBox");
			//通过这个方式来打log
			//auto str = ILBridge::Mono_String_FromCharPtr("__cpp_createBox");
			ILBridge::Test_DumpObj(str);
			{//gettran
				typedef void* (*icall)(void* pthis);
				auto func = (icall)ILBridge::il2cpp_resolve_icall("UnityEngine.GameObject::get_transform()");

				if (func != nullptr)
				{
					transform = func(sharedbox);
					auto str = ILBridge::il2cpp_string_new("__cpp_get_transform");
					ILBridge::Test_DumpObj(str);
				}
			}
			//create vector3
			{

				auto type = ILBridge::il2cppex_getclass("UnityEngine", "Vector3");
				typedef void (*ictorcall)(void*, float x, float y, float z, void*);
				auto v3ctor = ILBridge::il2cpp_class_get_method_from_name(type, ".ctor", 3);
				auto v3ctor2 = ILBridge::il2cpp_resolve_icall("UnityEngine.Vector3::.ctor(System.Single,System.Single,System.Single)");
				auto v3new = ILBridge::il2cpp_object_new(type);
				ILBridge::il2cpp_runtime_object_init(v3new);
				v3 = v3new;
				auto n9 = ILBridge::il2cpp_method_get_name(v3ctor);
				auto n1 = ILBridge::il2cpp_method_get_param_name(v3ctor, 0);
				auto n2 = ILBridge::il2cpp_method_get_param_name(v3ctor, 1);
				auto n3 = ILBridge::il2cpp_method_get_param_name(v3ctor, 2);
				//如果是值类型，可以从Object中unbox出来操作，所有的数学库都不要了，用cpp重写，需要的时候，再box进一个物体里
				//这个方式传值性能是挺惨的

				//对IL2cpp来说，是不需要box回去的，直接操作指针，即可，数据在object内部有留存
				//应该不需要box回去
				//((ictorcall)(((void**)v3ctor)[0]))(v3new, 0.03, 0.03, 0.03, NULL);
				//v3 = v3new;
				//float* datain = (float*)ILBridge::il2cpp_object_unbox(v3new);
				////datain[1] = 1.0;
				//float* datain2 = (float*)ILBridge::il2cpp_object_unbox(v3new);

				//float* myfloat = new float[3]{ 1, 3, 4 };

				//auto data = ILBridge::il2cpp_value_box(type, myfloat);

				//data = NULL;
			}
			auto str2 = ILBridge::Test_Log("__cpp_new v3 succ", ILBridge::EnumLogLevel::INFO);
			ILBridge::Test_DumpObj(str2);
			{
				typedef void* (*setpos)(void* trans, void*);
				auto typeobj = ILBridge::il2cppex_getclass("UnityEngine", "Transform");

				auto func = (setpos)ILBridge::il2cpp_resolve_icall("UnityEngine.Transform::set_position(UnityEngine.Vector3)");
				auto func2 = (setpos)ILBridge::il2cpp_resolve_icall("UnityEngine.Transform::INTERNAL_set_rotation(UnityEngine.Quaternion&)");
				//auto v3 = ILBridge::il2cpp_resolve_icall("UnityEngine.Transform::set_position(UnityEngine.Vector3&)");
				auto v13 = ILBridge::il2cpp_resolve_icall("UnityEngine.Transform::get_position()");
				auto v14 = ILBridge::il2cpp_resolve_icall("UnityEngine.Transform::get_parent()");
				auto v141 = ILBridge::il2cpp_resolve_icall("UnityEngine.Transform::get_root()");
				auto v142 = ILBridge::il2cpp_resolve_icall("UnityEngine.Transform::getroot()");
				auto m001 = ILBridge::il2cpp_class_get_method_from_name(typeobj, "set_position", -1);
				func = (setpos)(((void**)m001)[0]);
				if (func != nullptr)
				{
					auto str = ILBridge::il2cpp_string_new("Transform set_position ");
					ILBridge::Test_DumpObj(str);
					v3 = new float[3]{ 1, 2, 0 };
					func(transform, v3);
				}
			}
		}
		else if ((int64_t)p1 == 3)
		{

		}
		else if ((int64_t)p1 == 4)
		{
			//這個只能在IL2CPP環境搞
				//ILBridge::il2cppex_delegate_hotfix("", "TestClass", "xcpp_HotFix_tt", testFunc);
		}
		else if ((int64_t)p1 == 101)//测试错误 除0
		{
			int a = 5;
			int b = 0;
			int c = a / b;
		}
		else if ((int64_t)p1 == 102)//测试错误 null
		{
			ILBridge::deleil2cpp_add_internal_call ojb = NULL;
			ojb("abc", NULL);
		}
		else if ((int64_t)p1 == 103)//测试错误 越界
		{
			int* a8 = 0;
			int b = a8[8];
		}

		else if ((int64_t)p1 == 201)//测试
		{
			//auto type = ILBridge::Mono_GetType("", "TestClass");
			//auto obj = ILBridge::Mono_Object_New(type);
			//typedef void* (*setcall)(void* pthis, float value);
			//auto fieldset = (setcall)ILBridge::Mono_Type_GetFieldFunc_Set(type, "aa1");
			//fieldset(obj, 2.0f);
			//ILBridge::Test_DumpObj(obj);

			//typedef void (*tcall)(void* pthis);
			//auto func = (tcall)ILBridge::Mono_Type_GetMethod(type, "tt()");
			//func(obj);

			//typedef float (*getcall)(void* pthis);
			//auto fieldget = (getcall)ILBridge::Mono_Type_GetFieldFunc_Get(type, "aa1");
			//float v = fieldget(obj);
			//char buf[256];
			//sprintf_s(buf, 256, "v= %f ", v);

			//ILBridge::Test_Log(buf, ILBridge::EnumLogLevel::WARN);

			//auto stype = ILBridge::Mono_GetType("", "Sdata");
			//Sdata data;
			//data.a1 = 1;
			//data.v2 = 2;
			//data.v3 = 3;
			//auto ilstruct = ILBridge::Mono_Struct_FromPtr(stype, &data);
			//ILBridge::Test_DumpObj(ilstruct);
		}

	}

	if (cmdid == 2)
	{
		throw  std::logic_error("a c++ error.");
	}

	if (cmdid == 377)
	{
		if (p1 == 1)//reg hotfix string
		{
			std::string str((const char*)p2);
			int idot = str.find_last_of('.');
			std::string str_namespace("");
			if (idot > 0)
			{
				str_namespace = str.substr(0, idot);
				str = str.substr(idot + 1);
			}
			if (ILBridge::il2cpp_add_internal_call == NULL)
			{
				ILBridge::Test_Log("error::no il2cpp_add_internal_call", ILBridge::EnumLogLevel::ERR);
				return;
			}
			printf("name=%s", str.c_str());
			auto type = ILBridge::il2cppex_getclass(str_namespace.c_str(), str.c_str());
			{
				auto name = std::string((const char*)p2).append("::New");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_new_i);
			}
			{
				auto name = std::string((const char*)p2).append("::New_ByString");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_new_bystring_i);
			}
			{
				auto name = std::string((const char*)p2).append("::Clone");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_clone_i);
			}
			{
				auto name = std::string((const char*)p2).append("::Free");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_free_i);
			}
			{
				auto name = std::string((const char*)p2).append("::GetStringBuffer");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_getstring_unsafe_i);
			}
			{
				auto name = std::string((const char*)p2).append("::GetStringObject");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_getstring_safe_i);
			}
			{
				auto name = std::string((const char*)p2).append("::Append");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_append_i);
			}
			{
				auto name = std::string((const char*)p2).append("::AppendString");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_append_string_i);
			}
			{
				auto name = std::string((const char*)p2).append("::AppendInt32");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_append_int32_i);
			}
			{
				auto name = std::string((const char*)p2).append("::AppendInt32WithCStyleFormat");
				ILBridge::il2cpp_add_internal_call(name.c_str(), (Il2CppMethodPointer)string_append_int32_withcstyleformat_i);
			}
			int i = 4;
		}
	}
}
//Update方法，每帧来一次
void _userhandler_OnUpdate(float totaltime, float deltatime)
{

}
